/*** 
*  
 * this file should not be edited , because it is created by merge tool automatically. 
 * @author : Bodhi  
 * @date : 2016\01\12  
 * @desc : data adapter  
 *  
 */ 
  
"use strict";  
  
var Utils = this.Utils || (function ($) {
        var lazyAjax,
            keys,
            Iterator, collectNonEnumProps,
            curry,
            namespace,
            deeperObj,
            trim;

        lazyAjax = function () {
            var params = [].slice.call(arguments),
                url = params[ 0 ],
                type = 'GET',
                data = {},
                success;

            if ( params.length === 2 ) {
                if ( typeof params[ 1 ] === 'function' ) {
                    success = params[ 1 ];
                }
                else if ( typeof params[ 1 ] === 'object' ) {
                    data = params[ 1 ];
                }
            } else if ( params.length === 3 ) {
                success = params[ 2 ];

                if ( typeof params[ 1 ] === 'string' ) {
                    type = params[ 1 ];
                } else if ( typeof params[ 1 ] === 'object' ) {
                    data = params[ 1 ];
                }
            }

            $.ajax({
                url: url,
                dataType: 'html',
                type: type,
                data: data,
                beforeSend: function () {

                },
                success: function (json) {
                    if ( typeof json === 'string' ) {
                        try {
                            json = JSON.parse(json);
                        } catch ( e ) {
                            throw new TypeError('请确定接口的返回值格式');
                        }
                    }

                    if ( !!success && typeof success === 'function' ) {
                        success(json);
                    }
                },
                complete: function () {

                },
                error: function (data) {
                    console.info("error: " + data.responseText);
                }
            });
        };

        collectNonEnumProps = function (obj, keys) {
            var nonEnumerableProps = [ 'valueOf', 'isPrototypeOf', 'toString',
                'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString' ];
            var nonEnumIdx = nonEnumerableProps.length;
            var constructor = obj.constructor;
            var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;

            // Constructor is a special case.
            var prop = 'constructor';
            if ( _.has(obj, prop) && !_.contains(keys, prop) ) keys.push(prop);

            while ( nonEnumIdx-- ) {
                prop = nonEnumerableProps[ nonEnumIdx ];
                if ( prop in obj && obj[ prop ] !== proto[ prop ] && !_.contains(keys, prop) ) {
                    keys.push(prop);
                }
            }
        };

        keys = function (obj) {
            var objProto = Object.prototype,
                nativeKeys = objProto.keys,
                keys = [],
                hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');

            if ( !$.isPlainObject(obj) ) {
                return keys;
            }
            if ( !!nativeKeys ) {
                return nativeKeys(obj);
            }

            for ( var key in obj ) if ( objProto.hasOwnProperty.call(obj, key) ) {
                keys.push(key);
            }

            if ( hasEnumBug ) {
                collectNonEnumProps(obj, keys);
            }
            return keys;
        };

        /***
         * @author Bodhi
         * @date 2016/01/08
         * @param obj array or plainObject
         * @param type string
         * @param before callback
         * @returns object
         * @constructor
         */
        Iterator = function (obj, type, before) {
            'use strict';

            var jq = jQuery,
                i = 0,
                keyList = [],
                isPlainObject = jq.isPlainObject(obj);

            //if key is number and to sort.
            if ( !!type && type.toLowerCase() === 'asc' ) {
                keys.sort(function (x, y) {
                    if ( !isNaN(x) && !isNaN(y) ) {
                        return +x - +y;
                    }
                    return x - y;
                });
            }

            if ( $.isFunction(before) ) {
                before(keys);
            }

            return ({
                check: function () {
                    if ( !obj || (!isPlainObject) ) {
                        throw new TypeError('obj is not plain object.');
                    }
                    keyList = keys(obj);
                },
                idxCheck:function(){
                    if(i < 0 || i > keyList.length-1){
                        return undefined;
                    }
                    return this._index(i);
                },
                init: function () {
                    this.check();
                    return this;
                },
                hasNext: function () {
                    return i < keyList.length;
                },
                current: function () {
                    return this.idxCheck();
                },
                prev: function () {
                    --i;
                    return this.idxCheck();
                },
                next: function () {
                    ++i;
                    return this.idxCheck();
                },
                first: function () {
                    return this._index(0);
                },
                last: function () {
                    return this._index(keyList.length - 1);
                },
                index: function () {
                    return i;
                },
                toIndex: function (key) {
                    i = keyList.indexOf(key);
                    return this._index(i);
                },
                _index: function (idx) {
                    var key = keyList[ idx ];
                    return {key: key, value: obj[ key ]};
                }
            }.init());
        };

        curry = function () {

        };

        trim = function (str, sign) {
            return (function f(str, sign) {
                if ( typeof str === 'function' ) str = str();
                if ( str != undefined && ( sign === undefined || sign === '' || sign === 'ALL' || sign === 'A') ) {
                    return str.replace(/(^\s*)|(\s*$)/g, "");
                }

                sign = f(sign);

                if ( sign === 'L' ) {
                    return str.replace(/(^\s*)/g, "");
                } else if ( sign === 'R' ) {
                    return str.replace(/(\s*$)/g, "");
                }
            }(str, sign));
        };

        namespace = function (obj, str) {
            var i, keys, len, item,
                _obj = obj = obj || {};

            if ( typeof str === 'function' ) {
                str = str();
            }

            keys = str.split('.');

            for ( i = 0, len = keys.length; i < len; i++ ) {
                item = keys[ i ];
                _obj[ item ] = _obj[ item ] || {};
                _obj = _obj[ item ];
            }

            return _obj;
        };

        deeperObj = function (obj, str, time) {
            var _obj = obj || {},
                func = function () {
                    return (typeof str === 'function') && str() ||  (typeof str === 'string') && str;
                };

            while ( time-- ) {
                _obj = namespace(_obj, func());
            }

            return _obj;
        };

        return {
            keys: keys,
            lazyAjax: lazyAjax,
            Iterator: Iterator,
            trim: trim,
            curry: curry,
            namespace: namespace,
            deeperObj: deeperObj
        }
    }(jQuery));

/***
 *
 * @param data
 * @param childs
 * @constructor
 */
var Node = function (data, childs) {
	this.data = data;
	this.parent = undefined;
	this.childs = childs || [];     //childrens node list.
	this.height = 0;
};

Node.prototype = {
	constructor: Node,
	init: function () {
		var childs = this.childs;
		for (var i = 0; i < childs.length; i++) {
			childs[i].parent = data;
		}
	},
	isRoot: function () {
		return this.height === 0;
	},
	isLeaf: function () {
		return this.childs.length === 0;
	},
	append: function (node) {
		node.parent = this;
		this.childs.push(node);
	},
	parents:function(){
		var parentsData = [],
			node= this.cloneNode();

		while (node.height > 0) {
			parentsData.push(node.data);
			node = node.parent;
		}

		return parentsData;
	},
	cloneNode:function(){
		return $.extend(true,{},this);
	},
	toString: function () {
		console.log(this.data);
	}
};


/***
 * Tree
 * @param root
 * @constructor Tree
 */
var Tree = function (root) {
	this.root = root || new Node();
};

Tree.prototype = {
	constructor: Tree,
	isEmpty: function () {
		return this.root === undefined;
	},
	/***
	 *前序
	 */
	preorder: function (visit) {
		var root = this.root;

		(function f(node) {
			var childs = node.childs;
			console.log(node.data.title || {});
			$.isFunction(visit) && visit(node);

			if (!node.isLeaf()) {
				for (var i = 0, len = childs.length; i < len; i++) {
					node = f(childs[i]);
				}
			}
		}(root));
	},
	/**
	 * 层次
	 * @param visit
	 */
	levelPrint: function (visit) {
		var queue = [], root = this.root, node;

		(function () {
			if (root !== undefined) {
				queue.push(root);
			}

			while (queue.length !== 0) {
				node = queue.shift();
				$.isFunction(visit) && visit(node);
				queue = queue.concat(node.childs);
			}
		}());
	}
};

/***
 * json format for fuelex.tree js.
 * @param options
 * @constructor
 */
var DataSourceTree = function (options) {
	this._data = options.data;
	this._delay = options.delay;
};

DataSourceTree.prototype.data = function (options, callback) {
	var $data = null;

	if (!("name" in options) && !("type" in options)) {
		$data = this._data;//the root tree
		callback({data: $data});
		return;
	}
	else if ("type" in options && options.type == "folder") {
		if ("additionalParameters" in options && "children" in options.additionalParameters)
			$data = options.additionalParameters.children;
		else $data = {} //no data
	}

	if ($data != null)//this setTimeout is only for mimicking some random delay
		setTimeout(function () {
			callback({data: $data});
		}, parseInt(Math.random() * 500) + 200);
};

/***
 * Core.js
 * @author Bodhi
 * @date 2016\01\11
 * @desc interface json data tree adapter.
 *
 */
(function ($, Node, Tree, DataSourceTree, Utils) {
    var funcTreeBind,       //bind data to tree plugin.
        buildCommonTree,      //build tree
        buildHsfTree,
        funcAdapt,
        visitNode,
        dataSourceRes = {};

    funcTreeBind = function (res) {
        if ( $.isPlainObject(res) ) {
            var treeDataSource = new DataSourceTree({data: res});
            $('#nav_tree').ace_tree({
                dataSource: treeDataSource,
                loadingHTML: '<div class="tree-loading"><i class="icon-refresh icon-spin blue"></i></div>',
                'open-icon': 'icon-folder-open',
                'close-icon': 'icon-folder-close',
                multiSelect: false,
                'selectable': false,
                'selected-icon': null,
                'unselected-icon': null
            });
        }
    };

    /***
     * build the tree from json file , the json file format is like json/example.json
     * @param parent
     * @param json
     */
    buildCommonTree = function (parent, json) {
        (function f(parent, json) {
            var childs = json.childs;
            for ( var i = 0; i < childs.length; i++ ) {
                var item = childs[ i ],
                    node = new Node({
                        id: item.id,
                        title: item.title,
                        locale: item.locale,
                        description: item.description,
                        icon: item.icon
                    });

                parent.append(node);
                node.height = parent.height + 1;

                if ( item.childs !== undefined && item.childs !== 0 ) {
                    f(node, {childs: item.childs});
                }
            }
        }(parent, json));
    };

    /***
     * build the tree from json file , the json file format is like json/tree.json
     * @param parent
     * @param json
     */
    buildHsfTree = function (parent, json) {
        (function f(parent, json) {
            var it = new Utils.Iterator(json);

            do {
                var current = it.current(),
                    value = current.value,
                    owns = (value['owns'] || []),
                    node = new Node();


                node.data = {
                    title: value.title,
                    icon: value.icon || '',
                    description: value.description,
                    locale: current.key
                };

                parent.append(node);
                node.height = parent.height + 1;

                if (owns && owns.length > 0) {
                    for (var i = 0; i < owns.length; i++) {
                        var item = owns[i];
                        f(node, item);
                    }
                }
            } while (it.next() !== undefined);
        }(parent, json));

        return parent;
    };


    /**
     * 按照层次遍历访问每个节点并对该节点进行操作。 ! important
     * @param node
     */
    visitNode = function (node) {
        var type = node.childs && node.childs.length !== 0 ? 'folder' : 'item',
            data = node.data;

        if ( node.height === 0 ) {
            dataSourceRes = {};
            return;
        }

        (function (time, obj, parentsData) {
            var _obj;

            _obj = Utils.deeperObj(obj, function () {
                var pop = parentsData.pop(),
                    locale = pop !== undefined && pop.hasOwnProperty('locale') && pop.locale;

                return locale + '.additionalParameters.children';
            }, time);

            _obj[ data.locale ] = {name: data.title, type: type, icon: data.icon || ''};

            return obj;
        }(node.height - 1, dataSourceRes, node.parents()));
    };

    /***
     * list of action.
     * @param json
     */
    funcAdapt = function (json) {
        var root;

        if ( !json.hasOwnProperty('title') ) {
            root = new Node();
            root.height = 0;
        }

        new Tree(buildHsfTree(root, json)).levelPrint(visitNode);
        funcTreeBind(dataSourceRes);
    };


    /**
     * get data from server , pass an callback as parameter that deal with data.
     *
     */
    (function (callback) {
        var self = this;
        Utils.lazyAjax('json/data_tree.json', function (json) {
            if ( $.isFunction(callback) && json && json.data ) {
                callback.call(self, json.data);
            } else {
                throw new TypeError('please check json data.');
            }
        });
    }(funcAdapt));
}(jQuery, Node, Tree, DataSourceTree, Utils));

